home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
filesyst
/
dosfs
/
dmsdosfs.000
/
dmsdosfs
/
dmsdosfs-0.6.9b
/
dmsdos_std.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-29
|
25KB
|
907 lines
/*
linux/fs/dmsdos/dmsdos_std.c
DMSDOS filesystem: standard routines.
This file adapts the standard Linux filesystem interface to the dmsdos
routines and decides whether to call msdos/vfat or dmsdos for the desired
operation.
******************************************************************************
DMSDOS (Doublespace/Drivespace compressed MSDOS filesystem) for Linux
written 1995,1996 by Frank Gockel
(C) Copyright 1995,1996 by Frank Gockel
Some code of the dmsdos filesystem has been copied from the msdos filesystem
so there are the following additional copyrights:
(C) Copyright 1992,1993 by Werner Almesberger (msdos filesystem)
(C) Copyright 1994,1995 by Jacques Gelinas (mmap code)
(C) Copyright 1992-1995 by Linus Torvalds
The DMSDOS filesystem was inspired by the THS filesystem (a simple doublespace
DS-0-2 compressed read-only filesystem) written 1994 by Thomas Scheuermann.
The DMSDOS filesystem is distributed under the Gnu General Public Licence.
See file COPYING for details.
******************************************************************************
*/
#include <linux/sched.h>
#include <linux/ctype.h>
#include <linux/major.h>
#include <linux/blkdev.h>
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/locks.h>
#include <asm/segment.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/msdos_fs.h>
#include <linux/dmsdos_fs.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/shm.h>
#include <linux/mman.h>
#include <asm/system.h>
#ifdef __FOR_KERNEL_1_3_8x
#include <linux/module.h>
#else
/*define empty MOD macros for older kernels... in order to ignore module...*/
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#endif
#ifdef MODULE
#ifndef __FOR_KERNEL_1_3_8x
#error DMSDOS: module support requires newer kernel > 1.3.80, sorry.
#endif
#endif
/* default compression mode,
you should use READ_ONLY or GUESS, further possibilities see dmsdos_fs.h */
#define DEFAULT_COMP GUESS
/* default compression level -1 */
/* 0=least efficient but fastest compression
11=most efficient but slowest compression */
#define DEFAULT_CF 11
/* vfat support (only for kernel >= 1.3.81) */
#ifdef CONFIG_DMSDOS_UPON_VFAT
#define SUPPORT_VFAT
#endif
/* writable mmap support (requires kernel >=1.3.81) */
/* defining USE_READPAGE causes the driver to use the new mmap code.
WARNING: This is very _experimental_ and may crash your system horribly
and mess up your compressed _and_ uncompressed dos filesystems.
This is currently not tested enough, so be extremely careful. */
#ifdef __FOR_KERNEL_1_3_8x
#define USE_READPAGE
#endif
/* initialization routines.... */
static struct file_system_type dmsdos_fs_type =
{dmsdos_read_super,"dmsdos",1,NULL};
#ifdef __FOR_KERNEL_1_3_8x
#ifdef USE_READPAGE
/* must be known because this should be exported */
int dmsdos_readpage(struct inode *inode, struct page *page);
#endif
static struct symbol_table dmsdos_syms = {
#include<linux/symtab_begin.h>
X(dmsdos_readdir),
X(dmsdos_file_read),
X(dmsdos_file_write),
X(dmsdos_create),
X(dmsdos_lookup),
X(dmsdos_read_super),
X(dmsdos_rename),
X(dmsdos_unlink),
X(dmsdos_rmdir),
X(dmsdos_mkdir),
X(dmsdos_unlink_umsdos),
X(dmsdos_truncate),
X(dmsdos_mmap),
X(dmsdos_put_inode),
X(dmsdos_put_super),
X(dmsdos_statfs),
X(dmsdos_read_inode),
X(dmsdos_write_inode),
X(dmsdos_notify_change),
X(dmsdos_ioctl_dir),
X(dbltest),
X(dostest),
#ifdef USE_READPAGE
X(dmsdos_readpage),
#endif
#include<linux/symtab_end.h>
};
#endif
int init_dmsdos_fs(void)
{ int status;
status=register_filesystem(&dmsdos_fs_type);
#ifdef __FOR_KERNEL_1_3_8x
if(status==0)status=register_symtab(&dmsdos_syms);
#endif
return status;
}
#ifdef MODULE
int init_module(void)
{ return init_dmsdos_fs();
}
int cleanup_module(void)
{ return unregister_filesystem(&dmsdos_fs_type);
}
#endif /*MODULE*/
#ifdef SUPPORT_VFAT
extern Dblsb dblsb[];
extern int dbl_sb_dev[];
int isvfat(struct super_block*sb)
{ int i;
for(i=0;i<MAXDBLFILES;++i)
{ if(dbl_sb_dev[i]==sb->s_dev)
return (dblsb[i].s_support_lfn&4);
}
return 0;
}
#endif /* SUPPORT_VFAT */
#ifdef USE_READPAGE
/* Grmpf.... partially untested code. Don't know an application that does
writable mmaps, but it would be needed for testing this piece of code */
/* idea: kernel does buffer reads with bmap calculated buffers - impossible
for dmsdos. (see kernel mmap code).
kernel emulates writable mmap by calling file_write when no buffers
are present - should work for dmsdos.
so I do file_read-emulated readable mmaps here though the
generic_mmap function is used.
*/
int read_the_page(unsigned long address, unsigned long pos,
struct inode*inode, int fs_type)
{
unsigned int clear;
long gap; /* distance from eof to pos */
/*printk("DMSDOS: read_the_page\n");*/
address &= PAGE_MASK;
clear = 0;
gap = inode->i_size - pos;
if (gap <= 0){
/* mmaping beyond end of file */
clear = PAGE_SIZE;
}else{
int cur_read;
int need_read;
struct file filp;
if (gap < PAGE_SIZE){
clear = PAGE_SIZE - gap;
}
filp.f_reada = 0;
filp.f_pos = pos;
need_read = PAGE_SIZE - clear;
{
unsigned long cur_fs = get_fs();
set_fs (KERNEL_DS);
cur_read = fs_type ?
fat_file_read (inode,&filp,(char*)address
,need_read) :
dmsdos_file_read (inode,&filp,(char*)address
,need_read);
set_fs (cur_fs);
}
if (cur_read != need_read){
printk ("DMSDOS: Error while reading an mmap file %d <> %d\n"
,cur_read,need_read);
return -1;
}
}
if (clear > 0){
memset ((char*)address+PAGE_SIZE-clear,0,clear);
}
return 0;
}
int dmsdos_readpage(struct inode *inode, struct page *page)
{ unsigned long address;
int error = -1;
/*printk("DMSDOS: readpage %08lx\n", page_address(page));*/
address = page_address(page);
page->count++;
set_bit(PG_locked, &page->flags);
/* wie waers wenn ich jetzt einfach lese */
error=read_the_page(address,page->offset,inode,0);
if(error==0)set_bit(PG_uptodate, &page->flags);
clear_bit(PG_locked, &page->flags);
wake_up(&page->wait);
free_page(address);
return error;
}
#ifdef NEED_FAT_READPAGE
/* fat_readpage is missing in fat fs, so long..... */
int fat_readpage(struct inode *inode, struct page *page)
{ unsigned long address;
int error = -1;
/*printk("DMSDOS: fat_readpage %08lx\n", page_address(page));*/
address = page_address(page);
page->count++;
set_bit(PG_locked, &page->flags);
/* wie waers wenn ich jetzt einfach lese */
error=read_the_page(address,page->offset,inode,1);
if(error==0)set_bit(PG_uptodate, &page->flags);
clear_bit(PG_locked, &page->flags);
wake_up(&page->wait);
free_page(address);
return error;
}
#endif /* NEED_FAT_READPAGE */
#endif /* USE_READPAGE */
static int dmsdos_dir_read(struct inode * inode,struct file * filp, char * buf,int count)
{
return -EISDIR;
}
static struct file_operations dmsdos_dir_operations = {
NULL, /* lseek - default */
dmsdos_dir_read, /* read */
NULL, /* write - bad */
dmsdos_readdir, /* readdir */
NULL, /* select - default */
dmsdos_ioctl_dir, /* ioctl - default */
NULL, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
file_fsync /* fsync */
};
struct inode_operations dmsdos_dir_inode_operations = {
&dmsdos_dir_operations, /* default directory file-ops */
dmsdos_create, /* create */
dmsdos_lookup, /* lookup */
NULL, /* link */
dmsdos_unlink, /* unlink */
NULL, /* symlink */
dmsdos_mkdir, /* mkdir */
dmsdos_rmdir, /* rmdir */
NULL, /* mknod */
dmsdos_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
#ifdef __FOR_KERNEL_1_3_8x
NULL, /* readpage */
NULL, /* writepage */
#endif
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
#ifdef __FOR_KERNEL_1_3
int dmsdos_readdir(
struct inode *inode,
struct file *filp,
void *dirent,
filldir_t filldir)
{ int res;
/*printk("DMSDOS: readdir ino=%ld\n",inode->i_ino);*/
if(dostest(inode))
#ifdef __FOR_KERNEL_1_3_8x
res=fat_readdir(inode,filp,dirent,filldir);
#else
res=msdos_readdir(inode,filp,dirent,filldir);
#endif
else res=dmsdos_readdirx(inode,filp,dirent,filldir);
/*printk("DMSDOS: readdir finished res=%d\n",res);*/
return res;
}
#else
int dmsdos_readdir(
struct inode *inode,
struct file *filp,
struct dirent *dirent,
int count)
{ int res;
/*printk("DMSDOS: readdir ino=%ld\n",inode->i_ino);*/
if(dostest(inode)) res=msdos_readdir(inode,filp,dirent,count);
else res=dmsdos_readdirx(inode,filp,dirent,count);
/*printk("DMSDOS: readdir finished res=%d\n",res);*/
return res;
}
#endif
static struct file_operations dmsdos_file_operations = {
NULL, /* lseek - default */
dmsdos_file_read, /* read */
dmsdos_file_write, /* write */
NULL, /* readdir - bad */
NULL, /* select - default */
NULL, /* ioctl - default */
#ifdef USE_READPAGE
generic_file_mmap,
#else
dmsdos_mmap, /* mmap */
#endif
NULL, /* no special open is needed */
NULL, /* release */
file_fsync /* fsync */
};
struct inode_operations dmsdos_file_inode_operations = {
&dmsdos_file_operations, /* default file operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
#ifdef __FOR_KERNEL_1_3_8x
#ifdef USE_READPAGE
dmsdos_readpage,
#else
NULL, /* readpage */
#endif
NULL, /* writepage */
#endif
NULL, /* bmap */
dmsdos_truncate, /* truncate */
NULL, /* permission */
NULL /* smap */
};
static struct file_operations dmsdos_file_operations_1024 = {
NULL, /* lseek - default */
dmsdos_file_read, /* read */
dmsdos_file_write, /* write */
NULL, /* readdir - bad */
NULL, /* select - default */
NULL, /* ioctl - default */
#ifdef USE_READPAGE
generic_file_mmap,
#else
dmsdos_mmap, /* mmap */
#endif
NULL, /* no special open is needed */
NULL, /* release */
file_fsync /* fsync */
};
struct inode_operations dmsdos_file_inode_operations_1024 = {
&dmsdos_file_operations_1024, /* default file operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
#ifdef __FOR_KERNEL_1_3_8x
#ifdef USE_READPAGE
dmsdos_readpage,
#else
NULL, /* readpage */
#endif
NULL, /* writepage */
#endif
NULL, /* bmap */
dmsdos_truncate, /* truncate */
NULL, /* permission */
NULL /* smap */
};
int dmsdos_file_read(
struct inode *inode,
struct file *filp,
char *buf,
int count)
{ int res;
/*res=count;
printk("DMSDOS file_read ino=%ld pos=%u count=%d\n",inode->i_ino,
filp->f_pos,res);*/
if(dostest(inode))
#ifdef __FOR_KERNEL_1_3_8x
res=fat_file_read(inode,filp,buf,count);
#else
res=msdos_file_read(inode,filp,buf,count);
#endif
else res=dmsdos_file_readx(inode,filp,buf,count);
/*printk("DMSDOS: file_read finished res=%d\n",res);*/
return res;
}
int dmsdos_file_write(
struct inode *inode,
struct file *filp,
#ifdef __FOR_KERNEL_1_3
const
#endif
char *buf,
int count)
{ int res;
/*res=count;
printk("DMSDOS file_write ino=%ld pos=%u count=%d\n",inode->i_ino,
filp->f_pos,res);*/
if(dostest(inode))
#ifdef __FOR_KERNEL_1_3_8x
res=fat_file_write(inode,filp,buf,count);
#else
res=msdos_file_write(inode,filp,buf,count);
#endif
else res=dmsdos_file_writex(inode,filp,buf,count);
/*printk("DMSDOS: file_write finished res=%d\n",res);*/
return res;
}
int dmsdos_create(
struct inode *dir,
const char*name, int len, int mode, struct inode**result)
{ int res;
/*printk("DMSDOS create ino=%ld\n",dir->i_ino);*/
if(dostest(dir)) res=
#ifdef SUPPORT_VFAT
isvfat(dir->i_sb) ? vfat_create(dir,name,len,mode,result) :
#endif
msdos_create(dir,name,len,mode,result);
else res=dmsdos_createx(dir,name,len,mode,result);
/*printk("DMSDOS: create finished res=%d\n",res);*/
return res;
}
int dmsdos_unlink(struct inode *dir, const char*name, int len)
{ int res;
/*printk("DMSDOS unlink ino=%ld\n",dir->i_ino);*/
if(dostest(dir)) res=
#ifdef SUPPORT_VFAT
isvfat(dir->i_sb) ? vfat_unlink(dir,name,len) :
#endif
msdos_unlink(dir,name,len);
else res=dmsdos_unlinkx(dir,name,len);
/*printk("DMSDOS: unlink finished res=%d\n",res);*/
return res;
}
int dmsdos_mkdir(struct inode *dir, const char*name, int len, int mode)
{ int res;
/*printk("DMSDOS mkdir ino=%ld\n",dir->i_ino);*/
if(dostest(dir)) res=
#ifdef SUPPORT_VFAT
isvfat(dir->i_sb) ? vfat_mkdir(dir,name,len,mode) :
#endif
msdos_mkdir(dir,name,len,mode);
else res=dmsdos_mkdirx(dir,name,len,mode);
/*printk("DMSDOS: mkdir finished res=%d\n",res);*/
return res;
}
int dmsdos_rmdir(struct inode *dir, const char*name, int len)
{ int res;
/*printk("DMSDOS rmdir ino=%ld\n",dir->i_ino);*/
if(dostest(dir)) res=
#ifdef SUPPORT_VFAT
isvfat(dir->i_sb) ? vfat_rmdir(dir,name,len) :
#endif
msdos_rmdir(dir,name,len);
else res=dmsdos_rmdirx(dir,name,len);
/*printk("DMSDOS: rmdir finished res=%d\n",res);*/
return res;
}
int dmsdos_rename(struct inode *old_dir, const char*old_name, int old_len,
struct inode *new_dir, const char*new_name, int new_len
#ifdef __FOR_KERNEL_2_0_1
,int must_be_dir
#endif
)
{ int res;
/*printk("DMSDOS rename ino=%ld\n",old_dir->i_ino);*/
if(dostest(old_dir)&&dostest(new_dir))
res=
#ifdef SUPPORT_VFAT
isvfat(old_dir->i_sb) ?
vfat_rename(old_dir,old_name,old_len,
new_dir,new_name,new_len
#ifdef __FOR_KERNEL_2_0_1
,must_be_dir
#endif
) :
#endif
msdos_rename(old_dir,old_name,old_len,
new_dir,new_name,new_len
#ifdef __FOR_KERNEL_2_0_1
,must_be_dir
#endif
);
else res=dmsdos_renamex(old_dir,old_name,old_len,
new_dir,new_name,new_len
#ifdef __FOR_KERNEL_2_0_1
,must_be_dir
#endif
);
/*printk("DMSDOS: rename finished res=%d\n",res);*/
return res;
}
void dmsdos_truncate(struct inode *inode)
{ /*printk("DMSDOS: truncate ino=%ld\n",inode->i_ino);*/
if(dostest(inode))
#ifdef __FOR_KERNEL_1_3_8x
fat_truncate(inode);
#else
msdos_truncate(inode);
#endif
else dmsdos_truncatex(inode);
/*printk("DMSDOS truncate finished\n");*/
}
void dmsdos_put_inode(struct inode *inode)
{ /*printk("DMSDOS: put inode ino=%ld\n",inode->i_ino);*/
if(dostest(inode))
#ifdef __FOR_KERNEL_1_3_8x
fat_put_inode(inode);
#else
msdos_put_inode(inode);
#endif
else dmsdos_put_inodex(inode);
/*printk("DMSDOS put inode finished\n");*/
}
void dmsdos_put_super(struct super_block *sb)
{ /*printk("DMSDOS put super\n");*/
exit_dbl(sb);
#ifdef SUPPORT_VFAT
if(isvfat(sb))vfat_put_super(sb); else
#endif
msdos_put_super(sb);
/*printk("DMSDOS put super finished\n");*/
MOD_DEC_USE_COUNT;
}
static struct super_operations dmsdos_sops = {
dmsdos_read_inode,
dmsdos_notify_change,
dmsdos_write_inode,
dmsdos_put_inode,
dmsdos_put_super,
NULL, /* added in 0.96c */
dmsdos_statfs,
NULL
};
/* evaluates a single option
if not dmsdos, append to msdos option string
*/
void evaluate_option(char*option,char*msdosoptions,int*comp,int*cf,int*ilong,
int*vfat,int*low,int*nofix)
{ /*printk("DMSDOS: evaluate option: %s\n",option);*/
if(strncmp(option,"comp=",5)==0)
{ if(strncmp(option+5,"no",2)==0)*comp=UNCOMPRESSED;
if(strncmp(option+5,"ro",2)==0)*comp=READ_ONLY;
if(strncmp(option+5,"ds00",4)==0)*comp=DS_0_0;
if(strncmp(option+5,"ds01",4)==0)*comp=DS_0_1;
if(strncmp(option+5,"ds02",4)==0)*comp=DS_0_2;
if(strncmp(option+5,"jm00",4)==0)*comp=JM_0_0;
if(strncmp(option+5,"jm01",4)==0)*comp=JM_0_1;
if(strncmp(option+5,"sq00",4)==0)*comp=SQ_0_0;
if(strncmp(option+5,"guess",5)==0)*comp=GUESS;
}
else if(strncmp(option,"cf=",3)==0)
{ if(option[3]=='1'&&option[4]>='0'&&option[4]<='2')*cf=option[4]-'0'+9;
else if(option[3]>='1'&&option[3]<='9')*cf=option[3]-'0'-1;
}
else if(strncmp(option,"long=",5)==0)
{ if(strncmp(option+5,"on",2)==0)*ilong=1;
if(strncmp(option+5,"off",3)==0)*ilong=0;
if(strncmp(option+5,"auto",4)==0)*ilong=2;
if(strncmp(option+5,"always",6)==0)*ilong=17;
}
else if(strncmp(option,"vfat",4)==0)*vfat=1;
else if(strncmp(option,"low",3)==0)*low=1;
else if(strncmp(option,"nofix",5)==0)*nofix=1;
else
{ if(strlen(msdosoptions)!=0)strcat(msdosoptions,",");
strcat(msdosoptions,option);
}
}
struct super_block *dmsdos_read_super(struct super_block *sb,void *data,
int silent)
{ struct super_block *s;
int comp,cf,i,ilong,vfat,low,nofix;
char *options=data;
char myoptions[512];
char msdosoptions[512];
char * akt_option;
/*printk("DMSDOS read_super\n");*/
comp=DEFAULT_COMP;
cf=DEFAULT_CF;
ilong=2; /* auto lfn */
vfat=0; /* off */
low=0; /* no low option specified */
nofix=0; /* perform fixdir when drivespace 3 rw */
MOD_INC_USE_COUNT;
/* scan option string */
/*printk("DMSDOS: option string: %s\n",options);*/
if(options==NULL)msdosoptions[0]='\0';
else
{ /* copy option string */
strcpy(myoptions,options);
/* separate options */
akt_option=myoptions;
msdosoptions[0]='\0';
for(i=0;i<=strlen(options);++i)
{ if(myoptions[i]==','||myoptions[i]=='\0')
{ myoptions[i]='\0';
evaluate_option(akt_option,msdosoptions,&comp,&cf,&ilong,&vfat,
&low,&nofix);
akt_option=&(myoptions[i+1]);
}
}
}
/*printk("DMSDOS: msdosoptions: %s\n",msdosoptions);*/
s=
#ifdef SUPPORT_VFAT
vfat ? vfat_read_super(sb,msdosoptions,silent) :
#endif
msdos_read_super(sb,msdosoptions,silent);
if(s==NULL)
{ MOD_DEC_USE_COUNT;
return NULL;
}
s->s_op=&dmsdos_sops;
/* dmsdos fs must be read-only if msdos fs is read-only */
if(s->s_flags&MS_RDONLY)comp=READ_ONLY;
if(dbl_init(s,data,comp,cf,ilong,vfat,low,nofix)<0)
{ s->s_dev=0;
MOD_DEC_USE_COUNT;
return NULL;
}
/*printk("DMSDOS read_super finished\n");*/
return s;
}
#ifdef __FOR_KERNEL_1_3
void dmsdos_statfs(struct super_block *sb,struct statfs *buf,int i)
{ /*printk("DMSDOS statfs\n");*/
#ifdef __FOR_KERNEL_1_3_8x
fat_statfs(sb,buf,i);
#else
msdos_statfs(sb,buf,i);
#endif
/*printk("DMSDOS statfs finished\n");*/
}
#else
void dmsdos_statfs(struct super_block *sb,struct statfs *buf)
{ /*printk("DMSDOS statfs\n");*/
msdos_statfs(sb,buf);
/*printk("DMSDOS statfs finished\n");*/
}
#endif
void dmsdos_read_inode(struct inode *inode)
{ /*printk("DMSDOS read_inode ino=%ld\n",inode->i_ino);*/
if(dostest(inode))
{
#ifdef SUPPORT_VFAT
if(isvfat(inode->i_sb))vfat_read_inode(inode); else
#endif
msdos_read_inode(inode);
}
else dmsdos_read_inodex(inode);
/*printk("DMSDOS read inode finished\n");*/
}
void dmsdos_write_inode(struct inode *inode)
{ /*printk("DMSDOS write inode ino=%ld\n",inode->i_ino);*/
if(dostest(inode))
#ifdef __FOR_KERNEL_1_3_8x
fat_write_inode(inode);
#else
msdos_write_inode(inode);
#endif
dmsdos_write_inodex(inode);
/*printk("DMSDOS write inode finished\n");*/
}
int dmsdos_notify_change(struct inode * inode,struct iattr * attr)
{ int res;
/*printk("DMSDOS notify_change ino=%ld\n",inode->i_ino);*/
if(dostest(inode))res=
#ifdef __FOR_KERNEL_1_3_8x
fat_notify_change(inode,attr);
#else
msdos_notify_change(inode,attr);
#endif
else res=dmsdos_notify_changex(inode,attr);
/*printk("DMSDOS notify change finished res=%d\n",res);*/
return res;
}
/*
* Fill in the supplied page for mmap
*/
static unsigned long dmsdos_file_mmap_nopage(
struct vm_area_struct * area,
unsigned long address,
#ifndef __FOR_KERNEL_1_3_8x
unsigned long page,
#endif
int error_code)
{
struct inode * inode = area->vm_inode;
unsigned int clear;
int pos;
long gap; /* distance from eof to pos */
/*printk("DMSDOS_file_mmap_nopage\n");*/
#ifdef __FOR_KERNEL_1_3_8x
unsigned long int page = __get_free_page(GFP_KERNEL);
if(!page)return page;
#endif
address &= PAGE_MASK;
pos = address - area->vm_start + area->vm_offset;
clear = 0;
gap = inode->i_size - pos;
if (gap <= 0){
/* mmaping beyond end of file */
clear = PAGE_SIZE;
}else{
int cur_read;
int need_read;
struct file filp;
if (gap < PAGE_SIZE){
clear = PAGE_SIZE - gap;
}
filp.f_reada = 0;
filp.f_pos = pos;
need_read = PAGE_SIZE - clear;
{
unsigned long cur_fs = get_fs();
set_fs (KERNEL_DS);
cur_read = dmsdos_file_read (inode,&filp,(char*)page
,need_read);
set_fs (cur_fs);
}
if (cur_read != need_read){
printk ("DMSDOS: Error while reading an mmap file %d <> %d\n"
,cur_read,need_read);
}
}
if (clear > 0){
memset ((char*)page+PAGE_SIZE-clear,0,clear);
}
return page;
}
struct vm_operations_struct dmsdos_file_mmap = {
NULL, /* open */
NULL, /* close */
NULL, /* unmap */
NULL, /* protect */
NULL, /* sync */
NULL, /* advise */
dmsdos_file_mmap_nopage, /* nopage */
NULL, /* wppage */
NULL, /* swapout */
NULL, /* swapin */
};
/*
* This is used for a general mmap of a dmsdos file
* Returns 0 if ok, or a negative error code if not.
*/
int dmsdos_mmapx(struct inode*inode,struct file*file,struct vm_area_struct*vma)
{
/*printk("DMSDOS mmap ino=%ld\n",inode->i_ino);*/
if (vma->vm_flags & VM_SHARED) /* only PAGE_COW or read-only supported now */
return -EINVAL;
if (vma->vm_offset & (inode->i_sb->s_blocksize - 1))
return -EINVAL;
if (!inode->i_sb || !S_ISREG(inode->i_mode))
return -EACCES;
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
vma->vm_inode = inode;
inode->i_count++;
vma->vm_ops = &dmsdos_file_mmap;
return 0;
}
int dmsdos_mmap(struct inode*inode,struct file*file,struct vm_area_struct*vma)
{ int res;
/*printk("DMSDOS mmap ino=%ld\n",inode->i_ino);*/
if(dostest(inode)) res=
#ifdef __FOR_KERNEL_1_3_8x
fat_mmap(inode,file,vma);
#else
msdos_mmap(inode,file,vma);
#endif
else res=dmsdos_mmapx(inode,file,vma);
/*printk("DMSDOS mmap finished res=%d\n",res);*/
return res;
}
int dmsdos_lookup(struct inode *dir,const char *name,int len,
struct inode **result)
{ int res;
/*printk("DMSDOS lookup ino=%ld name=%s\n",dir->i_ino,name);*/
if(dostest(dir)) res=
#ifdef SUPPORT_VFAT
isvfat(dir->i_sb) ? vfat_lookup(dir,name,len,result) :
#endif
msdos_lookup(dir,name,len,result);
else res=dmsdos_lookupx(dir,name,len,result);
/*printk("DMSDOS lookup finished res=%d\n",res);*/
return res;
}